<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>大文件切片上传和断点续传 | Jaho’s Blog</title>
    <meta name="generator" content="VuePress 1.8.0">
    <link rel="icon" href="/favicon.ico">
    <link rel="manifest" href="/manifest.json">
    <meta name="description" content="记录日常学习工作">
    
    <link rel="preload" href="/assets/css/0.styles.5b8fe0a4.css" as="style"><link rel="preload" href="/assets/js/app.6514719e.js" as="script"><link rel="preload" href="/assets/js/2.ea114ffb.js" as="script"><link rel="preload" href="/assets/js/51.cb424f59.js" as="script"><link rel="preload" href="/assets/js/4.e093c564.js" as="script"><link rel="prefetch" href="/assets/js/10.13203aa5.js"><link rel="prefetch" href="/assets/js/11.099868c4.js"><link rel="prefetch" href="/assets/js/12.c8365e17.js"><link rel="prefetch" href="/assets/js/13.89751e7c.js"><link rel="prefetch" href="/assets/js/14.31f563eb.js"><link rel="prefetch" href="/assets/js/15.08b381b6.js"><link rel="prefetch" href="/assets/js/16.1a3867de.js"><link rel="prefetch" href="/assets/js/17.7dd4e0c6.js"><link rel="prefetch" href="/assets/js/18.907c4597.js"><link rel="prefetch" href="/assets/js/19.fac8aa1a.js"><link rel="prefetch" href="/assets/js/20.73fe0e75.js"><link rel="prefetch" href="/assets/js/21.5c50aa1c.js"><link rel="prefetch" href="/assets/js/22.83d03663.js"><link rel="prefetch" href="/assets/js/23.061e7ac0.js"><link rel="prefetch" href="/assets/js/24.cc7e9011.js"><link rel="prefetch" href="/assets/js/25.fa6c7aef.js"><link rel="prefetch" href="/assets/js/26.39392f70.js"><link rel="prefetch" href="/assets/js/27.204436be.js"><link rel="prefetch" href="/assets/js/28.3f54c157.js"><link rel="prefetch" href="/assets/js/29.799d048c.js"><link rel="prefetch" href="/assets/js/3.6c5d6214.js"><link rel="prefetch" href="/assets/js/30.deed02f3.js"><link rel="prefetch" href="/assets/js/31.5916873b.js"><link rel="prefetch" href="/assets/js/32.b0634144.js"><link rel="prefetch" href="/assets/js/33.734675b8.js"><link rel="prefetch" href="/assets/js/34.20404dc4.js"><link rel="prefetch" href="/assets/js/35.d93b829f.js"><link rel="prefetch" href="/assets/js/36.b0692d8d.js"><link rel="prefetch" href="/assets/js/37.3dffa306.js"><link rel="prefetch" href="/assets/js/38.04649a97.js"><link rel="prefetch" href="/assets/js/39.7dfcdc32.js"><link rel="prefetch" href="/assets/js/40.04914511.js"><link rel="prefetch" href="/assets/js/41.ced85449.js"><link rel="prefetch" href="/assets/js/42.72739213.js"><link rel="prefetch" href="/assets/js/43.de1cff16.js"><link rel="prefetch" href="/assets/js/44.48e301ae.js"><link rel="prefetch" href="/assets/js/45.870a7650.js"><link rel="prefetch" href="/assets/js/46.657f15b8.js"><link rel="prefetch" href="/assets/js/47.3df1bfdb.js"><link rel="prefetch" href="/assets/js/48.f4e4e774.js"><link rel="prefetch" href="/assets/js/49.632bf611.js"><link rel="prefetch" href="/assets/js/5.6531e181.js"><link rel="prefetch" href="/assets/js/50.a8018493.js"><link rel="prefetch" href="/assets/js/52.a9f595dc.js"><link rel="prefetch" href="/assets/js/53.cf8a9ec0.js"><link rel="prefetch" href="/assets/js/54.46d774a3.js"><link rel="prefetch" href="/assets/js/55.3574f9b8.js"><link rel="prefetch" href="/assets/js/56.baf60ba5.js"><link rel="prefetch" href="/assets/js/57.af42b559.js"><link rel="prefetch" href="/assets/js/58.9300cb59.js"><link rel="prefetch" href="/assets/js/6.00f437ec.js"><link rel="prefetch" href="/assets/js/7.58ac7166.js"><link rel="prefetch" href="/assets/js/8.1b9c5002.js"><link rel="prefetch" href="/assets/js/9.5c076362.js">
    <link rel="stylesheet" href="/assets/css/0.styles.5b8fe0a4.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/logo.png" alt="Jaho’s Blog" class="logo"> <span class="site-name can-hide">Jaho’s Blog</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/posts/" class="nav-link router-link-active">
  技术博客
</a></div> <a href="https://juejin.cn/user/26836627369806" target="_blank" rel="noopener noreferrer" class="repo-link">
    个人主页
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/posts/" class="nav-link router-link-active">
  技术博客
</a></div> <a href="https://juejin.cn/user/26836627369806" target="_blank" rel="noopener noreferrer" class="repo-link">
    个人主页
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><a href="/posts/" aria-current="page" class="sidebar-link">写在前面</a></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>工作问题解决</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/posts/项目问题解决/vuevite.html" class="sidebar-link">vue3+vite用proxy解决跨域及proxy原理解析</a></li><li><a href="/posts/项目问题解决/大文件.html" class="active sidebar-link">大文件切片上传和断点续传</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/posts/项目问题解决/代码优化.html" class="sidebar-link">实际工作中代码优化</a></li><li><a href="/posts/项目问题解决/组件问题.html" class="sidebar-link">解决组件传值问题</a></li><li><a href="/posts/项目问题解决/动态组件.html" class="sidebar-link">动态组件实践</a></li><li><a href="/posts/项目问题解决/大屏.html" class="sidebar-link">大屏九宫格视频</a></li><li><a href="/posts/项目问题解决/滚动.html" class="sidebar-link">Vue中Element表单定位滚动到校验错误位置</a></li><li><a href="/posts/项目问题解决/红绿灯.html" class="sidebar-link">Promise实现动态红绿灯切换</a></li><li><a href="/posts/项目问题解决/懒加载.html" class="sidebar-link">实现元素懒加载</a></li><li><a href="/posts/项目问题解决/小程序组件.html" class="sidebar-link">微信小程序封装组件</a></li><li><a href="/posts/项目问题解决/axios.html" class="sidebar-link">项目中对axios的整体封装</a></li><li><a href="/posts/项目问题解决/docker.html" class="sidebar-link">docker实践(附windows安装下载教程)</a></li><li><a href="/posts/项目问题解决/eltable.html" class="sidebar-link">el-table自定义表头及无数据状态</a></li><li><a href="/posts/项目问题解决/gojs.html" class="sidebar-link">gojs入门学习</a></li><li><a href="/posts/项目问题解决/react踩坑.html" class="sidebar-link">React踩坑</a></li><li><a href="/posts/项目问题解决/小程序踩坑.html" class="sidebar-link">小程序踩坑</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>JavaScript</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Css</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Nodejs</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Vue</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Git</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="大文件切片上传和断点续传"><a href="#大文件切片上传和断点续传" class="header-anchor">#</a> 大文件切片上传和断点续传</h1> <blockquote><p>在日常的开发中，项目中基本出现的最多的应该就是上传文件，对于文件的上传，我们可以分为多种形式，单文件上传、多文件上传、进度管控、拖拽上传、大文件上传。</p></blockquote> <blockquote><p>今天就把大文件上传来说一下，对于大文件的上传，我们需要知道有俩种做法，一种是切片上传，还有一种是断点续传：切片上传，顾名思义就是把我们的文件按<code>大小</code>或者<code>数量</code>进行分割切成小文件，然后按片进行上传。断点续传则是当我们的文件上传一半的时候，突然断网或者刷新页面，下次再上传该文件的时候，会跳过已经上传的文件片段，从<code>上一次上传</code>的地方继续上传。</p></blockquote> <h3 id="为什么要用hash命名文件"><a href="#为什么要用hash命名文件" class="header-anchor">#</a> 为什么要用hash命名文件</h3> <blockquote><p>上传到服务器的文件，如果俩个用户上传的文件名称相同的话，可能会被识别到文件已经存在，导致后端服务不会去再次上传新的图片，这样就会造成新图片无法上传，并且显示文件已经存在。hash是对上传文件的buffer进行读取，然后通过spkmd5插件来进行转换成hash值，如果文件上传的是一样的，那么buffer的值是一样，转成出来的hash值自然也是一样的，那么上传的时候同一个文件就不会因为hash名不同而存在服务端俩次。虽然文件hash处理一般是在服务端做，但也有可能存在某些情况需要前端来做这件事情。</p></blockquote> <h3 id="实现过程"><a href="#实现过程" class="header-anchor">#</a> 实现过程</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;container&quot;</span><span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;item&quot;</span><span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>h3<span class="token operator">&gt;</span>大文件上传<span class="token operator">&lt;</span><span class="token operator">/</span>h3<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span>section ref<span class="token operator">=</span><span class="token string">&quot;upload7&quot;</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;upload_box&quot;</span> id<span class="token operator">=</span><span class="token string">&quot;upload7&quot;</span><span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span>input  type<span class="token operator">=</span><span class="token string">&quot;file&quot;</span> <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;upload_inp&quot;</span> ref<span class="token operator">=</span><span class="token string">&quot;upload_inp&quot;</span><span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;upload_button_box&quot;</span><span class="token operator">&gt;</span>
                    <span class="token operator">&lt;</span>button <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;upload_button select&quot;</span> ref<span class="token operator">=</span><span class="token string">&quot;upload_button_select&quot;</span><span class="token operator">&gt;</span>上传图片<span class="token operator">&lt;</span><span class="token operator">/</span>button<span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;upload_progress&quot;</span> ref<span class="token operator">=</span><span class="token string">&quot;upload_progress&quot;</span><span class="token operator">&gt;</span>
                    <span class="token operator">&lt;</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">&quot;value&quot;</span> ref<span class="token operator">=</span><span class="token string">&quot;upload_progress_value&quot;</span><span class="token operator">&gt;</span><span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
                <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
            <span class="token operator">&lt;</span><span class="token operator">/</span>section<span class="token operator">&gt;</span>
        <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
    <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span>
</code></pre></div><p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/82b0d6c60a184f379892fbd90a91f7ff~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p> <h3 id="切片操作"><a href="#切片操作" class="header-anchor">#</a> 切片操作</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">let</span>   upload7 <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      upload_inp <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      upload_button_select <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      upload_progress <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      upload_progress_value <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token keyword">function</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
      upload7 <span class="token operator">=</span> upload7<span class="token punctuation">.</span>value
      upload_inp <span class="token operator">=</span> upload_inp<span class="token punctuation">.</span>value
      upload_button_select <span class="token operator">=</span> upload_button_select<span class="token punctuation">.</span>value
      upload_progress <span class="token operator">=</span> upload_progress<span class="token punctuation">.</span>value
      upload_progress_value <span class="token operator">=</span> upload_progress_value<span class="token punctuation">.</span>value
      upload_button_select<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        upload_inp<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
      upload_inp<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span><span class="token keyword">async</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">let</span> file <span class="token operator">=</span> upload_inp<span class="token punctuation">.</span>files<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>file<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token comment">//实现切片上传 </span>
        <span class="token comment">//思路，先按照最大大小切片 如果大于100片 则最多只能切100片</span>
        <span class="token keyword">let</span> max <span class="token operator">=</span> <span class="token number">1024</span><span class="token operator">*</span><span class="token number">10</span><span class="token punctuation">,</span>
            size <span class="token operator">=</span> file<span class="token punctuation">.</span>size<span class="token punctuation">,</span>
            count <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">ceil</span><span class="token punctuation">(</span>size<span class="token operator">/</span>max<span class="token punctuation">)</span><span class="token punctuation">,</span>
            index <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span>
            chunks <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
            <span class="token punctuation">{</span>
                <span class="token constant">HASH</span><span class="token punctuation">,</span>
                suffix
            <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">changeBuffer</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>count<span class="token operator">&gt;</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
          max <span class="token operator">=</span> size<span class="token operator">/</span><span class="token number">100</span>
          count <span class="token operator">=</span> <span class="token number">100</span>
        <span class="token punctuation">}</span>
        
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>当我们获取完页面的节点后，监听上传文件的变化事件，获取file进行切片，这里的file可以打印出来看下，其实file的原型上存在着Blob，对file的切片，实际上是对Blob的切片</p> <p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5a512bc1a1a5440cb9f1e647047acc51~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p> <p>切片的话我们分为数量和大小进行切片，写按规定大小进行切片，如果切完数量超过最大数量，则按最大数量来进行切片</p> <h3 id="转换buffer"><a href="#转换buffer" class="header-anchor">#</a> 转换Buffer</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token function-variable function">changeBuffer</span> <span class="token operator">=</span> <span class="token parameter">file</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token parameter">resolve</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
        <span class="token keyword">let</span> fileReader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileReader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        fileReader<span class="token punctuation">.</span><span class="token function">readAsArrayBuffer</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//读取文件转成Buffer数据</span>
        fileReader<span class="token punctuation">.</span><span class="token function-variable function">onload</span> <span class="token operator">=</span> <span class="token parameter">ev</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
            <span class="token keyword">let</span> buffer <span class="token operator">=</span> ev<span class="token punctuation">.</span>target<span class="token punctuation">.</span>result<span class="token punctuation">,</span>
                spark <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SparkMD5<span class="token punctuation">.</span>ArrayBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                <span class="token constant">HASH</span><span class="token punctuation">,</span>
                suffix<span class="token punctuation">;</span>
            spark<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>buffer<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token constant">HASH</span> <span class="token operator">=</span> spark<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            suffix <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.([a-zA-Z0-9]+)$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span>file<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
            <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
                buffer<span class="token punctuation">,</span>
                <span class="token constant">HASH</span><span class="token punctuation">,</span>
                suffix<span class="token punctuation">,</span>
                <span class="token literal-property property">filename</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HASH</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>suffix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>  
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span> 
</code></pre></div><p>使用<code>readAsArrayBuffer</code>对文件转换成buffer
<img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1d2d40abb9844de1bba3a76ce91ca685~tplv-k3u1fbpfcp-watermark.image?" alt="image.png">
利用SparkMD5插件来对文件的内容转换成hash</p> <p><img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a9d9d8d8b9b146bd84282dc7d48ccb33~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p> <blockquote><p>转换后即使文件名换了但是图片内容不换，生成的hash都是同一个值，因为这是根据文件的内容生成的hash，这点可以有效的防止同一张图片多次存在服务器中。</p></blockquote> <h3 id="存储切片"><a href="#存储切片" class="header-anchor">#</a> 存储切片</h3> <div class="language-js 存储切片 extra-class"><pre class="language-js"><code><span class="token comment">//存切片    </span>
        <span class="token keyword">while</span><span class="token punctuation">(</span>index<span class="token operator">&lt;</span>count<span class="token punctuation">)</span><span class="token punctuation">{</span>
          chunks<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
            <span class="token literal-property property">file</span><span class="token operator">:</span> file<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>index <span class="token operator">*</span> max<span class="token punctuation">,</span> <span class="token punctuation">(</span>index <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">*</span> max<span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token literal-property property">filename</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HASH</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">_</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token operator">+</span><span class="token number">1</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>suffix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span>
          index<span class="token operator">++</span>
        <span class="token punctuation">}</span>
        chunks<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">chunk</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
          <span class="token keyword">let</span> fm <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FormData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
          fm<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'file'</span><span class="token punctuation">,</span> chunk<span class="token punctuation">.</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span>
          fm<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'filename'</span><span class="token punctuation">,</span> chunk<span class="token punctuation">.</span>filename<span class="token punctuation">)</span><span class="token punctuation">;</span>
          instance<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/upload_chunk'</span><span class="token punctuation">,</span> fm<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">data</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
              <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">+</span>data<span class="token punctuation">.</span>code <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                  <span class="token function">complate</span><span class="token punctuation">(</span>count<span class="token punctuation">,</span><span class="token constant">HASH</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                  <span class="token keyword">return</span><span class="token punctuation">;</span>
              <span class="token punctuation">}</span>
              <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">reject</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>codeText<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
              <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'当前切片上传失败，请您稍后再试~~'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token comment">// clear();</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>接着上面的步骤，使用while循环把切片数据放到一个数组中，并且每次push都按照规定的切片大小进行切割，文件名自然是使用已经产生好的hash来拼接命名，当数组循环上传之后，我们可以看到浏览器网络会一个一个的发送请求</p> <p><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e275664c6694407496a9e8b6630a3c8c~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p> <h3 id="合并切片"><a href="#合并切片" class="header-anchor">#</a> 合并切片</h3> <p>后端通过接收切片后放到一个文件夹中，作为一个切片文件夹
<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/88b8ef5264934c43a3309c78eaabe5f2~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p> <p>前端循环切片上传到最后一个切片的时候，就去调用后端的合并切片接口，把对应hash下面的切片进行合并，生成一个正式的图片，这里后端部分暂时不做讲解，其实也是通过一些api对切片进行合并</p> <p><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/89367c3f4f06475493ee5024efab88ad~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p> <h3 id="断点续传"><a href="#断点续传" class="header-anchor">#</a> 断点续传</h3> <p>如果您已经理解了上面部分的内容，那么对于断点续传其实也不难理解</p> <blockquote><p>断点续传是针对切片上传的文件，对已经上传的切片不再重新进行上传，做法其实很简单，需要从服务端拿到已经上传的切片数组，比如服务端返回了1~10的切片，而要重新上传的文件也有一个切片数组1-100，那么上传时切片会判断1-10存在服务端，则跳过上传，做法如下</p></blockquote> <p>already表示已上传的切片</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 已经上传的无需在上传</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>already<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> already<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>chunk<span class="token punctuation">.</span>filename<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">complate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="最后"><a href="#最后" class="header-anchor">#</a> 最后</h3> <blockquote><p>本文主要是讲清楚大文件切片上传和断点上传的内容及其实现过程，讲解了在前端方面的大文件上传的知识，本文的技术代码来自b站视频，笔者只是学习后留作笔记使用</p></blockquote> <p>如果对您有帮助的话，请给我点给赞吧~文章不足之处还请各位不吝赐教</p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">2023-01-04 10:56:12</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/posts/项目问题解决/vuevite.html" class="prev">
        vue3+vite用proxy解决跨域及proxy原理解析
      </a></span> <span class="next"><a href="/posts/项目问题解决/代码优化.html">
        实际工作中代码优化
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"><!----><!----></div></div>
    <script src="/assets/js/app.6514719e.js" defer></script><script src="/assets/js/2.ea114ffb.js" defer></script><script src="/assets/js/51.cb424f59.js" defer></script><script src="/assets/js/4.e093c564.js" defer></script>
  </body>
</html>
